export default class Node {
    label: string
    key: string
    isFolder: boolean
    isCurrent: boolean
    isCheck: boolean
    isIndeterminate: boolean
    isLoadMore: boolean
    expanded: boolean
    visible: boolean
    loading: boolean
    disabled: boolean
    data: any
    level: number
    isFilter: boolean
    disabledCheckbox: boolean
    parent: Node
    children: Node[]
    total: number
    pageIndex: number
    pageSize: number
    loaded: boolean

    constructor (options) {
      this.init();

      for (const prop in options) {
        if (Object.prototype.hasOwnProperty.call(options, prop)) {
          this[prop] = options[prop];
        }
      }

      if (!this.parent || this.parent.expanded) {
        this.visible = true;
      } else {
        this.visible = false;
      }
    }

    init () {
      this.label = '';
      this.key = '';
      this.isFolder = false;
      this.isCurrent = false;
      this.isCheck = false;
      this.isIndeterminate = false;
      this.isLoadMore = false;
      this.expanded = false;
      this.visible = true;
      this.isFilter = true;
      this.loading = false;
      this.disabled = false;
      this.data = null;
      this.level = 0;
      this.disabledCheckbox = false;
      this.parent = null;
      this.children = [];
      this.total = 0;
      this.pageIndex = 0;
      this.pageSize = 10;
      this.loaded = false;
    }

    toggleExpand () {
      this.expanded = !this.expanded;
      if (this.expanded) {
        this.expand();
      } else {
        this.collapse();
      }
    }

    expand () {
      if (!this.isFolder || !this.visible) {
        return;
      }
      this.children.forEach(child => {
        if (child.isFilter) {
          child.visible = true;
          child.expanded && child.expand();
        }
      });
    }

    collapse () {
      if (!this.isFolder) {
        return;
      }

      this.children.forEach(child => {
        child.visible = false;
        child.expanded && child.collapse();
      });
    }

    toggleCurrent () {
      this.isCurrent = !this.isCurrent;
    }

    toggleLoading () {
      this.loading = !this.loading;
    }

    expandRoot () {
      this.traverseParent(node => {
        if (!node.expanded) {
          node.toggleExpand();
        }
      });
    }

    traverse (cb) {
      cb = typeof cb === 'function' ? cb : () => false;
      let stack = [];
      stack.push(this);

      while (stack.length) {
        const node = stack.pop();
        if (cb(node)) {
          break;
        } else {
          stack = stack.concat(node.children);
        }
      }
    }

    traverseParent (cb) {
      cb = typeof cb === 'function' ? cb : () => {};
      let node = this.parent;
      while (node) {
        const isBreak = cb(node);
        if (isBreak) {
          break;
        }

        node = node.parent;
      }
    }
}
